package com.pjb.springbootjjwt.store.server;

import com.pjb.springbootjjwt.store.utils.StringUtil;
import lombok.Data;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

@Data
public class AST {
    private Tree root = new Tree("root", "");

    public AST(String sql) {
        List<Tree> list = new ArrayList<>();

        while (true) {
            String sub = this.getChild(sql);
            if (!StringUtils.isEmpty(sub.trim())) {
                Tree tree = new Tree(sub);
                list.add(tree);
                sql = sql.replace(sub, "").replace("()", "@" + tree.id);
            }

            if (!isLoop(sql)) {  //循环结束时的处理
                list.add(new Tree(sql));
                break;
            }
        }

        for (Tree tree : list) {
            List<String> numList = Tree.getValueNumber(tree.value);
            if (numList.isEmpty()) {
                Tree.add(root, tree);
                continue;
            }

            List<Tree> parts = new ArrayList<>();
            for (String num : numList) {
                Tree part = Tree.getById(num, root);    // 如果value中有num，那么就是id为num的父节点
                if (part != null) parts.add(part);
            }
            if (!ObjectUtils.isEmpty(parts)) {
                Tree.addParent(tree, parts, root);
            }
        }
        System.out.println("root:" + root);
    }

    public static void main(String[] args) {
        new AST("select * from (select * from (select * from vv c) (select * from vv d) a) b");
    }

    private boolean isLoop(String sql) {
        if (sql.contains("()")) {
            sql = sql.replace("()", "");
        }
        return sql.contains("(") || sql.contains(")");
    }

    /**
     * 获取子查询
     *
     * @param sql
     * @return
     */
    private String getChild(String sql) {
        if (isLoop(sql)) {
            while (sql.contains("(") || sql.contains(")")) {
                if (sql.contains("(")) {
                    sql = sql.substring(sql.indexOf("(") + 1);
                    continue;
                }
                if (sql.contains(")")) {
                    sql = sql.substring(0, sql.indexOf(")"));
                    continue;
                }
            }
            return sql;
        }
        return "";
    }

    public void visit(Tree tree, List<Tree> trees, String parent) {
        Tree t = new Tree(tree.getId(), tree.getValue());
        t.parent = parent;
        // root节点不放入列表
        if (!t.id.equals("root")) {
            trees.add(t);
        }
        for (Tree node : tree.getNode()) {
            visit(node, trees, tree.id);
        }
    }

    @Data
    public static class Tree {

        String id;      //关键字id
        String parent;
        String value;   //节点的值

        List<Tree> node = new ArrayList<>();

        public Tree(String value) {
            this.id = StringUtil.random(6);
            this.value = value;
        }

        public Tree(String id, String value) {
            this.id = id;
            this.value = value;
        }

        /**
         * 获取节点的父节点
         *
         * @param c
         * @param root
         * @return
         */
        public static Tree getParent(Tree c, Tree root) {
            if (root == c) return root;
            if (!root.node.isEmpty())
                for (Tree a : root.node) {
                    if (a == c) return root;
                }
            for (Tree a : root.node) {
                return getParent(c, a);
            }
            return null;
        }

        /**
         * 根据id获取当前节点的父节点
         *
         * @param id
         * @return
         */
        public static Tree getParentById(String id, Tree root) {
            if (root.id.equals(id)) return root;
            if (!root.node.isEmpty())
                for (Tree a : root.node) {
                    if (a.id.equals(id)) return root;
                    return getParentById(id, a);
                }
            return null;
        }

        /**
         * 根据id获取当前节点
         *
         * @param id
         * @return
         */
        public static Tree getById(String id, Tree root) {
            if (root.id.equals(id)) return root;
            if (!root.node.isEmpty())
                for (Tree a : root.node) {
                    if (a.id.equals(id)) return a;
                }
            for (Tree a : root.node) {
                return getById(id, a);
            }
            return null;
        }

        /**
         * 获取value中的id
         *
         * @param value
         * @return
         */
        public static List<String> getValueNumber(String value) {
            String[] arr = value.split("\\s+");
            List<String> r = new ArrayList<>();
            for (String s : arr) {
                if (s.contains("@") && s.length() > 1) { // id不为空
                    r.add(s.substring(1));
                }
            }
            return r;
        }

        /**
         * 将节点添加到父节点下面
         *
         * @param p
         * @param part
         */
        public static void add(Tree p, Tree part) {
            p.node.add(part);
        }

        /**
         * 提取节点的父节点
         *
         * @param p
         * @param parts
         * @param root
         */
        public static void addParent(Tree p, List<Tree> parts, Tree root) {
            Tree parent = getParent(parts.get(0), root);
            p.node.addAll(parts);
            parent.node.removeAll(parts);

            parent.node.add(p);
        }

        public static void addParent(Tree p, Tree parts, Tree root) {
            Tree parent = getParent(parts, root);
            p.node.add(parts);
            parent.node.remove(parts);

            parent.node.add(p);
        }

        public static void main(String[] args) {
            Tree root = new Tree("root");
            for (int i = 0; i < 5; i++) {
                root.node.add(new Tree("a" + i));
            }
            for (int i = 0; i < 5; i++) {
                root.node.get(0).node.add(new Tree("b" + i));
            }
            Tree c = root.node.get(0).node.get(0);
            Tree node = getParent(c, root);
            System.out.println(node);

            Tree p = new Tree("p");
            addParent(p, root.node.get(0).node, root);
            System.out.println(root);
        }
    }

}
